//
// Created by song on 16-11-18.
//

#ifndef C0COMPILER_ASTNODE_H
#define C0COMPILER_ASTNODE_H


#include <vector>
#include "Token.h"
#include "../helper/Error.h"




enum ASTNodeType{
    SourceCode,
    Number,
    Identifier,
    CharConst,
    StringConst,
    ConstDeclar,
    VariableDeclar,
    ArrayDeclar,
    FunctionDeclar,
    Param,
    Block,
    IfStmt,
    WhileStmt,
    SwitchStmt,
    CaseSegment,
    DefaultSegment,
    AssignStmt,
    ReturnStmt,
    RelationExpr,
    AddSubExpr,
    MultiDivExpr,
    ArraySubscript,
    FunctionInvoke,
    ConditionExpr
};


class ASTNode{
private:
    map<string,string> _property;
    static map<ASTNodeType, string> astTypeStr;
    static map<ASTNodeType, string> init(){
        map<ASTNodeType, string> m;
        m[SourceCode] = "SourceCode";
        m[Number] = "Number";
        m[Identifier] = "Identifier";
        m[CharConst] = "CharConst";
        m[StringConst] = "StringConst";
        m[ConstDeclar] = "ConstDeclar";
        m[VariableDeclar] = "VariableDeclar";
        m[ArrayDeclar] = "ArrayDeclar";
        m[FunctionDeclar] = "FunctionDeclar";
        m[Param] = "Param";
        m[Block] = "Block";
        m[IfStmt] = "IfStmt";
        m[WhileStmt] = "WhileStmt";
        m[SwitchStmt] = "SwitchStmt";
        m[CaseSegment] = "CaseSegment";
        m[DefaultSegment] = "DefaultSegment";
        m[AssignStmt] = "AssignStmt";
        m[ReturnStmt] = "ReturnStmt";
        m[RelationExpr] = "RelationExpr";
        m[AddSubExpr] = "AddSubExpr";
        m[MultiDivExpr] = "MultiDivExpr";
        m[ArraySubscript] = "ArraySubscript";
        m[FunctionInvoke] = "FunctionInvoke";
        m[ConditionExpr] = "ConditionExpr";
        return m;
    };
public:
    ASTNode(ASTNodeType type):
            id(-1),
            astType(type),
            parent(NULL),
            start(-1),
            end(-1),
            needCheck(false)
    {}

    int id;
    ASTNodeType astType;
    vector<ASTNode*> children;
    ASTNode * parent;
    int start;
    int end;
    bool needCheck; // used when generate code.

    // the following properties' meaning are different in different ast node.
    TokenType contentType;
    int value;
    char ch;
    string content;

    string property(string key){
        if(_property.count(key)==0){
            Error::internal(Error::Key_Not_In_AST);
        }
        return _property[key];
    }

    void property(string key, string value){
        _property[key] = value;
    }

    void addChild(ASTNode* child){
        children.push_back( child );
        child->parent = this;
    }

    bool isLeaf(){
        return children.size() == 0;
    }

    string toString(){
        if(astTypeStr.count(astType)>0){
            return astTypeStr[astType];
        }else{
            Error::internal(Error::Should_Not_Happen);
        }
    }


};


#endif //C0COMPILER_ASTNODE_H
